﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows.Controls.Ribbon;
using SHomeWorkshop.LunarConcept.Controls;
using System.Xml;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.ModifingManager;
using System.Windows;
using SHomeWorkshop.LunarConcept.Widgets;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;

namespace SHomeWorkshop.LunarConcept.Commands
{
    /// <summary>
    /// 创建时间：2012年1月29日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：在当前选定的各ICanBeLinkedWidgets之间添加关系线。
    /// </summary>
    public static class InsertRelationsBetweenCommand
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态][构造方法]
        /// 
        /// ——此方法会初始化并向WPF系统注册一个RoutedUICommand。
        /// </summary>
        static InsertRelationsBetweenCommand()//类型构造器
        {
            routedUICmd = new RoutedUICommand(
                "InsertRelationsBetweenCommand",
                "InsertRelationsBetweenCommand",
                typeof(InsertRelationsBetweenCommand),//创建RoutedUICommand对象
                null);//本程序考虑支持“命令模式”因此，这些命令完全没有必要直接支持快捷键。

            cmdBinding.Command = routedUICmd;
            cmdBinding.CanExecute += new CanExecuteRoutedEventHandler(cmdBinding_CanExecute);
            cmdBinding.Executed += new ExecutedRoutedEventHandler(cmdBinding_Executed);
        }

        #endregion

        #region 字段与属性===================================================================================================

        private static CommandBinding cmdBinding = new CommandBinding();
        /// <summary>
        /// 用在主窗口CommandBindings集合中的命令绑定。
        /// 
        /// 它的Command是RoutedUICommand。
        /// ——因此，RoutedUICommand是否可以运行将由CmdBinding的CanExecute事件决定。
        /// ——而且，RoutedUICommand的执行也是通过CmdBinding的Execute事件来进行的。
        /// </summary>
        public static CommandBinding CmdBinding
        {
            get { return cmdBinding; }
        }

        private static RoutedUICommand routedUICmd;
        /// <summary>
        /// [只读静态属性]表示在WPF系统中注册的一个RoutedUICommand。
        /// ——必须和CommandBinding配合才能使用。
        ///     CommandBinding要添加到主窗口的CommandBindings集合中；
        ///     RoutedUICommand则要向WPF系统注册。
        ///     
        /// ★说明：使用静态属性是因为这样在Xaml代码中比较便于绑定。
        /// </summary>
        public static RoutedUICommand RoutedUICmd
        {
            get { return routedUICmd; }
        }

        #endregion

        #region 方法=========================================================================================================

        /// <summary>
        /// 判断命令是否可以执行。
        /// ——由于可以直接调用Execute()方法，因此，即使被禁用，也不是不能执行相关功能！！！
        /// </summary>
        static void cmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            //考虑到性能问题，全部取消此判断。反正执行时会判断。
            //if (Globals.MainWindow == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //EditorManager manager = Globals.MainWindow.EditorManager;
            //if (manager == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //PageEditor pe = manager.GetMainSelectedPageEditor();
            //if (pe == null) { e.CanExecute = false; return; }

            //int canBeLinkedWidgetCount = 0;
            //int mainICW = 0;

            //List<Widget> selectedWidgets = pe.GetSelectedWidgetsList(true);
            //foreach (Widget w in selectedWidgets)
            //{
            //    if (w is Widgets.Interfaces.ICanBeLinkedWidget == false) continue;

            //    canBeLinkedWidgetCount++;
            //    if (w.IsMainSelected)
            //    {
            //        mainICW++;
            //    }
            //}

            ////至少两个实体部件之间才能添加关系。
            //if (canBeLinkedWidgetCount < 2 || mainICW <= 0)//活动用以决定连接线的首端点。
            //{
            //    e.CanExecute = false;
            //    return;
            //}

            e.CanExecute = true;
            return;
        }

        /// <summary>
        /// 命令被触发时，会调用本事件处理器方法。
        /// ——本方法实际上是调用ExeCute()这个静态方法来实现特定功能。
        /// </summary>
        static void cmdBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            LunarMessage.Warning(Execute(e.Parameter));
        }

        /// <summary>
        /// [公开静态方法]即使此命令处于禁用状态，也可以通过代码调用此方法来执行特定任务！！！
        /// 
        /// 当被绑定的命令被调用（触发）时，会引发cmdBinding_Executed事件。
        /// 在cmdBinding_Executed事件处理器方法中已添加了调用Execute()方法的代码。
        /// 
        /// ——因此，触发命令，就相当于调用此方法！！！
        /// </summary>
        public static string Execute(object parameter)
        {
            bool toMeLine = false;//默认添加的是以我为中心的发散线(FromMe)。

            String lineType = parameter as string;
            if (string.IsNullOrEmpty(lineType) == false && lineType == "ToMe")
            {
                toMeLine = true;
            }

            if (Globals.MainWindow == null) return "　　未找到Globals.MainWindow。";

            EditorManager manager = Globals.MainWindow.EditorManager;
            if (manager == null) return "　　未找到页面管理器。";

            PageEditor pe = manager.GetMainSelectedPageEditor();
            if (pe == null) return "　　未找到活动页面。";

            List<ICanBeLinkedWidget> otherCanBeLinkedWidgets = new List<ICanBeLinkedWidget>();
            Widgets.Interfaces.ICanBeLinkedWidget mainCW = null;

            List<Widget> selectedWidgets = pe.GetSelectedWidgetsList(true);
            foreach (Widget w in selectedWidgets)
            {
                Widgets.Interfaces.ICanBeLinkedWidget icw = w as Widgets.Interfaces.ICanBeLinkedWidget;
                if (icw == null) continue;

                if (icw.IsMainSelected)
                {
                    mainCW = icw;
                }
                else
                {
                    otherCanBeLinkedWidgets.Add(icw);
                }
            }

            if (otherCanBeLinkedWidgets.Count < 1 || mainCW == null) return "　　没有找到连接的起点部件或终点部件。";

            ModifingInfo info = new ModifingInfo() { ModifingDescription = "添加多重关系" };
            manager.GetSelectedPageEditorStatus(info);
            manager.GetSelectedWidgetStatus_Old(info);
            manager.GetSelectedWidgetStatus_New(info);
            ModifingItem<Action, ModifingInfo> mi = new ModifingItem<Action, ModifingInfo>(info);

            XmlNode widgetSetNode = pe.WidgetSetNode;

            //删除原有的所有连接线
            manager.ClearWidgetsSelection();
            List<Widgets.Interfaces.ILinkableLine> linkedLines = pe.GetLinkedLines(mainCW);
            if (linkedLines.Count > 0)
            {
                foreach (ILinkableLine il in linkedLines)
                {
                    il.IsSelected = true;
                }

                DeleteWidgetsCommand.Execute(false);
            }

            foreach (ICanBeLinkedWidget cw in otherCanBeLinkedWidgets)
            {
                XmlNode newNodeLine;

                switch (Globals.MainWindow.EditorManager.MouseDraggingType)
                {
                    case Enums.PageDraggingType.InsertBezierLine:
                        {
                            newNodeLine = InsertBezierLines(pe, mainCW, mi, widgetSetNode, cw, toMeLine);

                            break;
                        }
                    case Enums.PageDraggingType.InsertPolyLine:
                        {
                            newNodeLine = InsertPolylines(pe, mainCW, mi, widgetSetNode, cw, toMeLine);

                            break;
                        }
                    default:
                        {
                            newNodeLine = InsertStraitLines(pe, mainCW, mi, widgetSetNode, cw, toMeLine);

                            break;
                        }
                }

                cw.IsSelected = true;
            }

            mainCW.IsMainSelected = true;

            if (manager.ContinueInsertWidget == false)
            {
                manager.MouseDraggingType = Enums.PageDraggingType.None;
                Globals.MainWindow.UnCheckInsertLineWidgetToggleButtons(null);
            }

            manager.RegisterModifingItem(mi);

            return string.Empty;
        }

        private static XmlNode InsertStraitLines(PageEditor pe, Widgets.Interfaces.ICanBeLinkedWidget mainCW, ModifingItem<Action, ModifingInfo> mi, XmlNode widgetSetNode, ICanBeLinkedWidget cw, bool toMeLine)
        {
            XmlNode newNodeLine;
            StraitLineWidget linkedLine;
            newNodeLine = widgetSetNode.AppendXmlAsChild(Properties.Resources.StraitLineXml);
            linkedLine = new StraitLineWidget(pe);

            linkedLine.XmlData = newNodeLine;
            linkedLine.NewID();
            Rect rectStart;
            Rect rectEnd;

            if (toMeLine)
            {
                linkedLine.EndMasterId = mainCW.Id;
                linkedLine.StartMasterId = cw.Id;

                pe.AddWidget(linkedLine as Widget);
                rectStart = new Rect(cw.TopLeft, cw.BottomRight);
                rectEnd = new Rect(mainCW.TopLeft, mainCW.BottomRight);
            }
            else
            {
                linkedLine.StartMasterId = mainCW.Id;
                linkedLine.EndMasterId = cw.Id;

                pe.AddWidget(linkedLine as Widget);
                rectStart = new Rect(mainCW.TopLeft, mainCW.BottomRight);
                rectEnd = new Rect(cw.TopLeft, cw.BottomRight);
            }

            Point startCenter = new Point(rectStart.Left + (rectStart.Width / 2), rectStart.Top + (rectStart.Height / 2));
            Point endCenter = new Point(rectEnd.Left + (rectEnd.Width / 2), rectEnd.Top + (rectEnd.Height / 2));

            PointToRect.ArrowPoints aptStart = PointToRect.GetCrossPointToRect(rectStart, endCenter);
            PointToRect.ArrowPoints aptEnd = PointToRect.GetCrossPointToRect(rectEnd, startCenter);

            linkedLine.StartPoint = aptStart.Top;
            linkedLine.EndPoint = aptEnd.Top;

            Action actionAddStraitLine = new Action(ActionType.WidgetAdded,
                pe.Id, linkedLine.Id, null, linkedLine.XmlData.OuterXml);

            mi.AddAction(actionAddStraitLine);

            return newNodeLine;
        }

        private static XmlNode InsertPolylines(PageEditor pe, Widgets.Interfaces.ICanBeLinkedWidget mainCW, ModifingItem<Action, ModifingInfo> mi, XmlNode widgetSetNode, ICanBeLinkedWidget cw, bool toMeLine)
        {
            XmlNode newNodeLine;
            newNodeLine = widgetSetNode.AppendXmlAsChild(Properties.Resources.PolyLineXml);
            PolyLineWidget linkedLine = new PolyLineWidget(pe);

            linkedLine.XmlData = newNodeLine;
            linkedLine.NewID();
            linkedLine.StartMasterId = mainCW.Id;
            linkedLine.EndMasterId = cw.Id;

            pe.AddWidget(linkedLine as Widget);

            Action actionAddStraitLine = new Action(ActionType.WidgetAdded,
                pe.Id, linkedLine.Id, null, linkedLine.XmlData.OuterXml);

            mi.AddAction(actionAddStraitLine);

            pe.RefreshLinkedLines(mi, linkedLine);
            return newNodeLine;
        }

        private static XmlNode InsertBezierLines(PageEditor pe, Widgets.Interfaces.ICanBeLinkedWidget mainCW, ModifingItem<Action, ModifingInfo> mi, XmlNode widgetSetNode, ICanBeLinkedWidget cw, bool toMeLine)
        {
            XmlNode newNodeLine;
            newNodeLine = widgetSetNode.AppendXmlAsChild(Properties.Resources.BezierLineXml);
            BezierLineWidget linkedLine = new BezierLineWidget(pe);

            linkedLine.XmlData = newNodeLine;
            linkedLine.NewID();
            linkedLine.StartMasterId = mainCW.Id;
            linkedLine.EndMasterId = cw.Id;

            pe.AddWidget(linkedLine as Widget);
            Rect rectStart = new Rect(mainCW.TopLeft, mainCW.BottomRight);
            Rect rectEnd = new Rect(cw.TopLeft, cw.BottomRight);

            Point startCenter = new Point(rectStart.Left + (rectStart.Width / 2), rectStart.Top + (rectStart.Height / 2));
            Point endCenter = new Point(rectEnd.Left + (rectEnd.Width / 2), rectEnd.Top + (rectEnd.Height / 2));

            PointToRect.ArrowPoints aptStart = PointToRect.GetCrossPointToRect(rectStart, endCenter);
            PointToRect.ArrowPoints aptEnd = PointToRect.GetCrossPointToRect(rectEnd, startCenter);

            linkedLine.StartPoint = aptStart.Top;
            linkedLine.EndPoint = aptEnd.Top;

            linkedLine.StartCPPoint = new Point(aptStart.Top.X + (aptEnd.Top.X - aptStart.Top.X) / 3,
                aptStart.Top.Y + (aptEnd.Top.Y - aptStart.Top.Y) / 3);
            linkedLine.EndCPPoint = new Point(aptStart.Top.X + 2 * (aptEnd.Top.X - aptStart.Top.X) / 3,
                aptStart.Top.Y + 2 * (aptEnd.Top.Y - aptStart.Top.Y) / 3);

            Action actionAddStraitLine = new Action(ActionType.WidgetAdded,
                pe.Id, linkedLine.Id, null, linkedLine.XmlData.OuterXml);

            mi.AddAction(actionAddStraitLine);
            return newNodeLine;
        }

        #endregion
    }
}
